package com.delete.executors;

import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

import com.delete.action.XMLExecutor;
import com.kevin.enums.DBType;

public class ExecutorFactory {
	private final static String CONFIG = "src//main//resources//";	
	private static String configName = CONFIG + "kndata-config.xml";
	
	private static Map<String,XMLExecutor> executorMap = new HashMap<>();
	private static String defaultExecutorName = StringUtils.EMPTY;
	
	static{
		loadConfig();
	}
	
	public static void configure(String configFilename){
		configName = configFilename;
	}
	
	public static String getDefaultExecutorName(){
		if(StringUtils.isNotEmpty(defaultExecutorName)){
			return defaultExecutorName;
		}else{
			if(executorMap.size() == 0){
				throw new ExecutorException("do not have any executor!");
			}else{
				String executorName = StringUtils.EMPTY;
				for (Entry<String, XMLExecutor> entry : executorMap.entrySet()) {
					executorName = entry.getKey();
					break;
		        }
				defaultExecutorName = executorName;
				return executorName;
			}
		}
	}
	
	public static MExecutor getDefaultExecutor(){
		String executorName = getDefaultExecutorName();
		return getExecutor(executorName);
	}
	
	public static MExecutor getExecutor(String executorName){
		if(executorMap.size() == 0){
			throw new ExecutorException("do not have any executor!");
		}
		if(StringUtils.isEmpty(executorName)){
			if(StringUtils.isNotEmpty(defaultExecutorName)){
				return buildExecutor(executorMap.get(defaultExecutorName));
			}else{		
				MExecutor executor = null;
				for (Entry<String, XMLExecutor> entry : executorMap.entrySet()) {
					executor = buildExecutor(entry.getValue());
					break;
		        }
				return executor;
			}
		}else{
			return buildExecutor(executorMap.get(executorName));
		}
	}
	
	private static MExecutor buildExecutor(XMLExecutor xml){
		MExecutor executor = null;
		if(StringUtils.isEmpty(xml.getDataSoruce())){
			executor = new MExecutor(xml.getProperties());
		}else{
			executor = new MExecutor(xml.getDataSoruce(), xml.getProperties());
		}
		
		
		executor.setExecutorName(xml.getName());
		DBType dbtype = xml.getDbType();
		executor.setDbType(dbtype);
		switch (dbtype) {
		case MYSQL:
			executor.setPrefix('?');
			break;
		case MSSQL:
		case SQLITE:
		case SYBASE:
			executor.setPrefix('@');
			break;
		case ORACLE:
			executor.setPrefix(':');
			break;
		default:
			break;
		}
		return executor;
	}
	
	@SuppressWarnings("unchecked")
	private static void loadConfig(){
		try{
			InputStream inputStream = new FileInputStream(configName);
			InputStreamReader reader = new InputStreamReader(inputStream,"UTF-8");
			Document document = new SAXBuilder().build(reader);
			Element rootElement = document.getRootElement();
			defaultExecutorName = rootElement.getAttributeValue("default");
			List<Element> exeEleList = rootElement.getChildren();
			for (Element exeEle : exeEleList) {	 
				Element dsEle = exeEle.getChild("dataSource");
				List<Element> propEleList = dsEle.getChildren();
				Properties properties = new Properties(); 	
				for (Element propEle : propEleList) {
					String name = propEle.getAttributeValue("name");
					String val = propEle.getAttributeValue("value");
					if(StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(val)){
						properties.setProperty(name, val);	
					}
				}		
				String clazz = dsEle.getAttributeValue("class");		
				String exeName = exeEle.getAttributeValue("name");		
				DBType dbtype = DBType.valueOf(exeEle.getAttributeValue("type"));
				XMLExecutor xmlExe = new XMLExecutor();
				
				xmlExe.setDataSoruce(clazz);
				xmlExe.setDbType(dbtype);
				xmlExe.setName(exeName);
				xmlExe.setProperties(properties);
				
				executorMap.put(exeName, xmlExe);
			}	
		}catch(Exception ex){
			ex.printStackTrace();
			throw new ExecutorException(ex);
		}
	}
}
